﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace EBA.IoC
{
    public static class WindowsAssembly
    {
        static WindowsAssembly()
        {
            
        }

        public static IEnumerable<Type> GetTypes()
        {
            foreach (Assembly assembly in WindowsAssembly.GetAssemblies())
            {
                foreach (var type in assembly.TryGetTypes())
                {
                    yield return type;
                }
            }
        }

        public static IEnumerable<Assembly> GetAssemblies(string searchPattern = "*.dll")
        {
            return GetAssemblies(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, i=>i.Name.EndsWith(searchPattern.Substring(1)));
        }

        public static IEnumerable<Assembly> GetAssemblies(Func<FileInfo, bool> predicate)
        {
            return GetAssemblies(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, predicate);
        }

        public static IEnumerable<Assembly> GetAssemblies(string folder, Func<FileInfo, bool> predicate)
        {
            var lib = new System.IO.DirectoryInfo(folder);

            var loaded = new Dictionary<string, Assembly>();

            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                loaded.Add(assembly.Location, assembly);
            }

            foreach (var file in lib.GetFiles().Where(i => predicate(i)))
            {
                if (loaded.ContainsKey(file.FullName))
                {
                    yield return loaded[file.FullName];
                }
                else
                {
                    var assemblyName = Assembly.ReflectionOnlyLoadFrom(file.FullName);//avoid to load assembly twice.

                    var assembly = loaded.Where(i => i.Value.FullName == assemblyName.FullName).Select(i=>i.Value).FirstOrDefault();

                    if (assembly != null)
                    {
                        yield return assembly;
                    }
                    else
                    {
                        assembly = Assembly.LoadFrom(file.FullName);
                        loaded[file.FullName] = assembly;
                        yield return assembly;
                    }
                }
            }
        }


    }
}